#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <math.h>
#include <iostream>
#include <fstream>
#include "DataStructures/FLR/FLRFile.h"
#include "DataStructures/EmptySpaceMgr.h"
#include "DataStructures/BlocksFile.h"
#include "DataStructures/Block.h"
#include "DataStructures/Hash/ExtensibleHash.h"
#include "DataStructures/Hash/BasicHashTable.h"
#include "DataStructures/Hash/HashRecord.h"
#include "DataStructures/BTree/BTree.h"
#include "Parser/DistritoParser.h"
#include "Parser/EleccionParser.h"
#include "Configuration/Properties.h"
#include "VotingActions.h"
#include "Crypto/RSA.h"
#include "AntiCrypto/RSABreaker.h"
#include "AntiCrypto/VigenereBreaker.h"

using namespace std;

void usage(char* progname) {
	fprintf(stdout, "Usage:\n");
	fprintf(stdout, "%s -h\t\t\t\tDisplay this message and exit\n", progname);
	fprintf(stdout, "%s -V --version\t\t\tDisplay version\n", progname);
}

void version() {
	fprintf(stdout, "Voto Electronico\n");
	fprintf(stdout, "75.06 - Organización de Datos\n");
	fprintf(stdout, "2do Cuat. 2011\n");
	fprintf(stdout, "---------------------------------------------\n");
	fprintf(stdout, "Desarrollado por:\n");
	fprintf(stdout, "\n");
	fprintf(stdout, "\tBujan Belen []\n");
	fprintf(stdout, "\tSoria Lorena []\n");
	fprintf(stdout, "\tEzequiel Aceto [84316]\n");
	fprintf(stdout, "---------------------------------------------\n");
}

void testBTree() {

	BTree* bTree = new BTree("testBTree",3*sizeof(unsigned long)+7);

	char data[10];
	unsigned long datalen = 0;

	char* data2 = NULL;
	unsigned long datalen2 = 0;

	for (unsigned long f = 0; f < 5; f++) {
		cout << "F: " << f << " =";
		if (bTree->get(f,&data2,&datalen2)) {
			for (int i = 0; i < datalen2; i++) {
				cout << data2[i];
			}
		}
		else {
			cout << "NOT";
		}
		if (data2 != NULL) {
			free(data2);
			data2 = NULL;
		}

		cout << endl;
	}

	data[0] = 'a';
	data[1] = 'c';
	data[2] = 'e';
	datalen = 3;

	if (bTree->put(1,data,datalen) == true) {
		cout << "OK." << endl;
	}
	else {
		cerr << "Error." << endl;
	}

	//////////////////////////

	data[0] = 'm';
	data[1] = 'b';
	data[2] = 'b';
	datalen = 3;

	if (bTree->put(2,data,datalen) == true) {
		cout << "OK." << endl;
	}
	else {
		cerr << "Error." << endl;
	}

	//////////////////////////

	data[0] = 'b';
	data[1] = 'e';
	data[2] = 'l';
	data[3] = 'e';
	data[4] = 'n';
	datalen = 5;

	if (bTree->put(2,data,datalen) == true) {
		cout << "OK." << endl;
	}
	else {
		cerr << "Error." << endl;
	}

	data[0] = 'l';
	data[1] = 'o';
	data[2] = 'r';
	data[3] = 'e';
	datalen = 4;

	if (bTree->put(3,data,datalen) == true) {
		cout << "OK." << endl;
	}
	else {
		cerr << "Error." << endl;
	}

	delete bTree;
}

int main(int argc, char** argv) {
/*
	VigenereBreaker* romper = new VigenereBreaker();
	string filePath = "/home/kimi/FiUBA/7506/TPs/TP1/files/test_input/kasiski";
			
	bool res = romper->breakByKasiskiAttack(filePath, filePath+"_kasiski");

	cout << "RES: " << res << endl;
	*/
/*
	Properties*props = new Properties("/home/kimi/FiUBA/7506/TPs/TP1/dist/config.properties");

	RSABreaker* breaker = new RSABreaker();

	bool res = breaker->breakByForceAttack(props);

	cout << "broken: " << res << endl;
*/

	//// IMPORTANTE!!! El archivo de administradores ahora esta encriptado!
	//// Hay un comando que agarra el archivo, lo encripta, y reemplaza su contenido.
	//// tienen que ejecutar el programa con ese comando para encriptar, antes de usarlo

	VotingActions* actions = new VotingActions("config.properties");

	actions->doAction(argc,argv);

	delete actions;

//	RSA * rsa = new RSA(1);
/*
	unsigned long n, phi;
	cout << "Generando N y Phi" << endl;
	rsa->generateNAndPhi(&n,&phi);
	unsigned long pk, pu;
	cout << "Generando PK y PU" << endl;
	rsa->generatePrivateAndPublicKey(n,phi,&pk,&pu);

	//rsa->decryptBinaryFile(pk,n,"testRSA","test");
	ofstream plainFile;
	plainFile.open("test",fstream::trunc|fstream::binary);

	char * data = new char[1024];
	for (unsigned int i = 0; i < 1024; i++)
		data[i] = (char)i;

	plainFile.write(data,1024*sizeof(char));
	plainFile.flush();
	plainFile.close();
*/

//	unsigned long pu = 1385, pk = 497, n = 2773;
/*
	//rsa->encryptBinaryFile(pu,n,"test","testRSA");
	rsa->decryptBinaryFile(pk,n,"/home/kimi/FiUBA/7506/TPs/TP1/files/work/archivoVotantesRecords_rsa",
			"/home/kimi/FiUBA/7506/TPs/TP1/files/work/archivoVotantesRecords2");
*/
	/*
	ifstream f1, f2;
	f1.open("/home/kimi/FiUBA/7506/TPs/TP1/files/work/archivoVotantesRecords",fstream::in|fstream::binary);
	f2.open("/home/kimi/FiUBA/7506/TPs/TP1/files/work/archivoVotantesRecords2",fstream::in|fstream::binary);

	char c1, c2;


	for (unsigned long i = 0; i < 4100; i++) {

		f1.read(&c1,sizeof(char));
		f2.read(&c2,sizeof(char));

		if (c1 != c2)
		cout << "index: "<< i << " :: " <<(unsigned long)(c1&0xFF) << " != " << (unsigned long)(c2&0xFF) << endl;

	}

	cout << "Done";

/// USO DE RSA para (des)encriptar un numero, un string y un archivo
/*
	RSA * rsa = new RSA(NULL);
	unsigned long n, phi;
	cout << "Generando N y Phi" << endl;
 	rsa->generateNAndPhi(&n,&phi);
	unsigned long pk, pu;
	cout << "Generando PK y PU" << endl;
	rsa->generatePrivateAndPublicKey(n,phi,&pk,&pu);

// NUMERO 720
	unsigned long encrypted = rsa->encrypt(pu,n,720);
	cout << "encryted " << encrypted << endl;
	unsigned long decrypted = rsa->decrypt(pk,n,encrypted);
	cout << "decrypted " << decrypted << endl;


// STRING msg
	string msg = string("Hola Francisco, como te va? Bienvenido =) Esperemos que le hagas buena compania a Belu, no hagas pis en su cama, ni le muerdas los zapatos!");
	string str = rsa->encrypt(pu,n,msg);
	cout << msg <<"= " << str << endl;
	cout << "MSG= " << rsa->decrypt(pk,n,str) << endl;

// archivos de propiedades
	if (rsa->encrypt(pu,n,"Debug/config.properties","Debug/encrypted.properties")) {
		cout << "archivos encriptados" << endl;
	}
	else {
		cerr << "Error al encriptar archivos "<< endl;
	}

	if (rsa->decrypt(pk,n,"Debug/encrypted.properties","Debug/new.properties")) {
		cout << "archivos desencriptados" << endl;
	}
	else {
		cerr << "Error al desencriptar archivos "<< endl;
	}
*/
	return 0;
}
